#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <signal.h>
#include <pthread.h>
#include <time.h>
#include <errno.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/extensions/XTest.h>
#include <ctype.h>

#define MAX_HOTKEYS 10
#define PASSWORD "root"
#define DEBUG 0

typedef struct {
    int key_code;
    int modifiers; // 修饰键状态
    void (*callback)(void);
    const char *description;
} Hotkey;

typedef struct {
    int running;
    Hotkey hotkeys[MAX_HOTKEYS];
    int hotkey_count;
    pthread_t listener_thread;
    Display *xdisplay; // 用于模拟输入
    int current_modifiers; // 当前按下的修饰键状态
} HotkeyManager;

HotkeyManager hotkey_mgr = {0};

// 日志函数
void log_message(const char* message) {
    if (DEBUG) {
        time_t now = time(NULL);
        struct tm *tm_info = localtime(&now);
        printf("[%02d:%02d:%02d] %s\n", 
               tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec, message);
    }
}

// 字符到KeySym的映射函数
KeySym char_to_keysym(char c) {
    // 处理数字
    if (isdigit(c)) {
        return XK_0 + (c - '0');
    }
    
    // 处理小写字母
    if (islower(c)) {
        return XK_a + (c - 'a');
    }
    
    // 处理大写字母
    if (isupper(c)) {
        return XK_A + (c - 'A');
    }
    
    // 处理特殊字符
    switch (c) {
        case '!': return XK_exclam;
        case '@': return XK_at;
        case '#': return XK_numbersign;
        case '$': return XK_dollar;
        case '%': return XK_percent;
        case '^': return XK_asciicircum;
        case '&': return XK_ampersand;
        case '*': return XK_asterisk;
        case '(': return XK_parenleft;
        case ')': return XK_parenright;
        case '-': return XK_minus;
        case '_': return XK_underscore;
        case '=': return XK_equal;
        case '+': return XK_plus;
        case '[': return XK_bracketleft;
        case ']': return XK_bracketright;
        case '{': return XK_braceleft;
        case '}': return XK_braceright;
        case ';': return XK_semicolon;
        case ':': return XK_colon;
        case '\'': return XK_apostrophe;
        case '"': return XK_quotedbl;
        case ',': return XK_comma;
        case '.': return XK_period;
        case '<': return XK_less;
        case '>': return XK_greater;
        case '/': return XK_slash;
        case '?': return XK_question;
        case '\\': return XK_backslash;
        case '|': return XK_bar;
        case '`': return XK_grave;
        case '~': return XK_asciitilde;
        case ' ': return XK_space;
        default: return (KeySym)c;
    }
}

// 检查设备是否为键盘
int is_keyboard_device(const char *device_path) {
    int fd = open(device_path, O_RDONLY);
    if (fd == -1) return 0;
    
    unsigned long ev_bits = 0;
    if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), &ev_bits) < 0) {
        close(fd);
        return 0;
    }

    int is_kbd = (ev_bits & (1 << EV_KEY)) && (ev_bits & (1 << EV_REP));
    close(fd);
    return is_kbd;
}

// 查找输入设备
char* find_input_device() {
    FILE *fp;
    char *dev_path = NULL;
    char path[256];
    char line[256];
    
    fp = fopen("/proc/bus/input/devices", "r");
    if (!fp) return NULL;
    
    while (fgets(line, sizeof(line), fp)) {
        if (strstr(line, "Handlers=")) {
            char *handler = strstr(line, "event");
            if (handler) {
                int event_num;
                if (sscanf(handler, "event%d", &event_num) == 1) {
                    snprintf(path, sizeof(path), "/dev/input/event%d", event_num);
                    if (is_keyboard_device(path)) {
                        dev_path = strdup(path);
                        break;
                    }
                }
            }
        }
    }
    fclose(fp);
    return strdup(dev_path);
}

// 初始化X11显示
int init_xdisplay() {
    hotkey_mgr.xdisplay = XOpenDisplay(NULL);
    if (!hotkey_mgr.xdisplay) {
        log_message("警告: 无法打开X显示，模拟输入功能将不可用");
        return 0;
    }
    return 1;
}

// 释放所有按下的修饰键
void release_all_modifiers() {
    if (!hotkey_mgr.xdisplay) return;
    
    log_message("释放所有修饰键...");
    
    // 释放Ctrl键
    KeyCode ctrl_keycode = XKeysymToKeycode(hotkey_mgr.xdisplay, XK_Control_L);
    if (ctrl_keycode) {
        XTestFakeKeyEvent(hotkey_mgr.xdisplay, ctrl_keycode, False, CurrentTime);
    }
    
    // 释放Shift键
    KeyCode shift_keycode = XKeysymToKeycode(hotkey_mgr.xdisplay, XK_Shift_L);
    if (shift_keycode) {
        XTestFakeKeyEvent(hotkey_mgr.xdisplay, shift_keycode, False, CurrentTime);
    }
    
    // 释放Alt键
    KeyCode alt_keycode = XKeysymToKeycode(hotkey_mgr.xdisplay, XK_Alt_L);
    if (alt_keycode) {
        XTestFakeKeyEvent(hotkey_mgr.xdisplay, alt_keycode, False, CurrentTime);
    }
    
    // 释放Super键
    KeyCode super_keycode = XKeysymToKeycode(hotkey_mgr.xdisplay, XK_Super_L);
    if (super_keycode) {
        XTestFakeKeyEvent(hotkey_mgr.xdisplay, super_keycode, False, CurrentTime);
    }
    
    XFlush(hotkey_mgr.xdisplay);
    usleep(100000); // 等待100ms确保修饰键释放
    hotkey_mgr.current_modifiers = 0;
}

// 修复的模拟键盘输入函数 - 确保没有修饰键被按下
void simulate_keyboard(const char* password) {
    if (!hotkey_mgr.xdisplay) {
        log_message("错误: X显示未初始化");
        return;
    }
    
    log_message("开始模拟键盘输入...");
    
    // 首先释放所有可能按下的修饰键
    release_all_modifiers();
    
    // 短暂延迟确保系统处理了修饰键释放
    usleep(200000); // 200ms
    
    for (int i = 0; password[i] != '\0'; i++) {
        KeySym keysym = char_to_keysym(password[i]);
        KeyCode keycode = XKeysymToKeycode(hotkey_mgr.xdisplay, keysym);
        
        if (keycode) {
            // 模拟按键按下和释放
            XTestFakeKeyEvent(hotkey_mgr.xdisplay, keycode, True, CurrentTime);
            XTestFakeKeyEvent(hotkey_mgr.xdisplay, keycode, False, CurrentTime);
            XFlush(hotkey_mgr.xdisplay);
            usleep(50000); // 50ms 延迟
            
            if (DEBUG) {
                printf("输入字符: %c (KeySym: %lu, KeyCode: %u)\n", 
                       password[i], keysym, keycode);
            }
        } else {
            printf("警告: 无法找到字符 '%c' 的键码\n", password[i]);
        }
    }
    
    // 模拟回车键
    KeyCode enter_keycode = XKeysymToKeycode(hotkey_mgr.xdisplay, XK_Return);
    if (enter_keycode) {
        XTestFakeKeyEvent(hotkey_mgr.xdisplay, enter_keycode, True, CurrentTime);
        XTestFakeKeyEvent(hotkey_mgr.xdisplay, enter_keycode, False, CurrentTime);
        XFlush(hotkey_mgr.xdisplay);
        log_message("回车键已发送");
    } else {
        printf("错误: 无法找到回车键的键码\n");
    }
    
    log_message("键盘模拟完成");
}

// 注册热键
int hotkey_register(int key_code, int modifiers, void (*callback)(void), const char* description) {
    if (hotkey_mgr.hotkey_count >= MAX_HOTKEYS) {
        log_message("错误: 热键数量达到上限");
        return 0;
    }
    
    Hotkey *hotkey = &hotkey_mgr.hotkeys[hotkey_mgr.hotkey_count];
    hotkey->key_code = key_code;
    hotkey->modifiers = modifiers;
    hotkey->callback = callback;
    hotkey->description = description;
    
    hotkey_mgr.hotkey_count++;
    
    log_message(description);
    return 1;
}

// 检查热键是否匹配
int is_hotkey_match(int key_code, int key_value, int modifier_state, Hotkey *hotkey) {
    if (key_value != 1) return 0;
    
    // 检查按键代码和修饰键状态
    int match = (key_code == hotkey->key_code) && 
                ((modifier_state & hotkey->modifiers) == hotkey->modifiers);
    
    if (match && DEBUG) {
        printf("热键匹配: key_code=%d, modifiers=0x%x, expected_modifiers=0x%x\n",
               key_code, modifier_state, hotkey->modifiers);
    }
    
    return match;
}

// 底层输入设备监听线程
void* input_device_listener(void* arg) {
    char* device_path = find_input_device();
    if (!device_path) {
        log_message("错误: 找不到可用的输入设备");
        return NULL;
    }
    
    printf("使用输入设备: %s\n", device_path);
    
    int fd = open(device_path, O_RDONLY | O_NONBLOCK);
    if (fd < 0) {
        log_message("错误: 无法打开输入设备");
        free(device_path);
        return NULL;
    }
    
    struct input_event ev;
    int modifier_state = 0;
    
    log_message("开始监听输入事件...");
    
    while (hotkey_mgr.running) {
        int bytes = read(fd, &ev, sizeof(ev));
        
        if (bytes == sizeof(ev)) {
            if (ev.type == EV_KEY) {
                if (DEBUG) {
                    printf("输入事件: type=%d, code=%d, value=%d\n", 
                           ev.type, ev.code, ev.value);
                }
                
                // 更新修饰键状态
                switch (ev.code) {
                    case KEY_LEFTCTRL:
                    case KEY_RIGHTCTRL:
                        if (ev.value) modifier_state |= 1;
                        else modifier_state &= ~1;
                        break;
                    case KEY_LEFTSHIFT:
                    case KEY_RIGHTSHIFT:
                        if (ev.value) modifier_state |= 2;
                        else modifier_state &= ~2;
                        break;
                    case KEY_LEFTALT:
                    case KEY_RIGHTALT:
                        if (ev.value) modifier_state |= 4;
                        else modifier_state &= ~4;
                        break;
                    case KEY_LEFTMETA:
                    case KEY_RIGHTMETA:
                        if (ev.value) modifier_state |= 8;
                        else modifier_state &= ~8;
                        break;
                }
                
                // 更新全局修饰键状态
                hotkey_mgr.current_modifiers = modifier_state;
                
                // 检查热键匹配
                for (int i = 0; i < hotkey_mgr.hotkey_count; i++) {
                    if (is_hotkey_match(ev.code, ev.value, modifier_state, &hotkey_mgr.hotkeys[i])) {
                        log_message(hotkey_mgr.hotkeys[i].description);
                        if (hotkey_mgr.hotkeys[i].callback) {
                            // 在新线程中执行回调，避免阻塞输入监听
                            pthread_t callback_thread;
                            if (pthread_create(&callback_thread, NULL, 
                                             (void* (*)(void*))hotkey_mgr.hotkeys[i].callback, NULL) == 0) {
                                pthread_detach(callback_thread);
                            }
                        }
                        break;
                    }
                }
            }
        } else if (bytes == -1 && errno != EAGAIN) {
            break;
        } else {
            usleep(10000);
        }
    }
    
    close(fd);
    free(device_path);
    log_message("输入设备监听线程已停止");
    return NULL;
}


// 安全地设置输入焦点
int safe_set_input_focus(Window window) {
    if (!hotkey_mgr.xdisplay || !window) return 0;
    
    // 检查窗口是否存在且可映射
    XWindowAttributes attr;
    if (!XGetWindowAttributes(hotkey_mgr.xdisplay, window, &attr)) {
        log_message("无法获取窗口属性");
        return 0;
    }
    
    if (attr.map_state != IsViewable) {
        log_message("窗口不可见，尝试映射");
        XMapWindow(hotkey_mgr.xdisplay, window);
        XFlush(hotkey_mgr.xdisplay);
        usleep(500000); // 等待500ms
    }
    
    // 使用更安全的方式设置焦点
    // 首先尝试将窗口提到前面
    XRaiseWindow(hotkey_mgr.xdisplay, window);
    XFlush(hotkey_mgr.xdisplay);
    
    // 使用不同的重定向策略尝试
    int success = 0;
    
    // 方法1: 使用RevertToParent
    XSetInputFocus(hotkey_mgr.xdisplay, window, RevertToParent, CurrentTime);
    XFlush(hotkey_mgr.xdisplay);
    usleep(100000); // 等待100ms
    
    // 检查焦点是否设置成功
    Window focus;
    int revert;
    XGetInputFocus(hotkey_mgr.xdisplay, &focus, &revert);
    if (focus == window) {
        success = 1;
    } else {
        // 方法2: 使用RevertToPointerRoot
        XSetInputFocus(hotkey_mgr.xdisplay, window, RevertToPointerRoot, CurrentTime);
        XFlush(hotkey_mgr.xdisplay);
        usleep(100000);
        
        XGetInputFocus(hotkey_mgr.xdisplay, &focus, &revert);
        if (focus == window) {
            success = 1;
        }
    }
    
    return success;
}


// 改进的窗口查找函数 - 查找登录相关窗口
Window find_login_window() {
    if (!hotkey_mgr.xdisplay) return 0;
    
    Window root = DefaultRootWindow(hotkey_mgr.xdisplay);
    Window *children;
    unsigned int nchildren;
    Window found = 0;
    
    if (!XQueryTree(hotkey_mgr.xdisplay, root, &root, &root, &children, &nchildren)) {
        return 0;
    }
    
    // 查找可能的登录窗口
    for (unsigned int i = 0; i < nchildren; i++) {
        XTextProperty text_prop;
        if (XGetWMName(hotkey_mgr.xdisplay, children[i], &text_prop)) {
            if (text_prop.value) {
                char *name = (char*)text_prop.value;
		printf("name is :%s\n",name);
                // 放宽匹配条件，查找任何可能的登录相关窗口
                if (strstr(name, "mate-sceensaver")) {
                    printf("找到可能的登录窗口: %s\n", name);
                    found = children[i];
                    XFree(text_prop.value);
                    break;
                }
                XFree(text_prop.value);
            }
        }
        
        // 检查窗口类名
        XClassHint class_hint;
        if (XGetClassHint(hotkey_mgr.xdisplay, children[i], &class_hint)) {
            if (class_hint.res_name && class_hint.res_class) {
                if (strstr(class_hint.res_name, "login") || 
                    strstr(class_hint.res_class, "screensaver") ||
                    strstr(class_hint.res_class, "lock")) {
                    printf("找到登录窗口类: %s - %s\n", class_hint.res_name, class_hint.res_class);
                    found = children[i];
                    XFree(class_hint.res_name);
                    XFree(class_hint.res_class);
                    break;
                }
                XFree(class_hint.res_name);
                XFree(class_hint.res_class);
            }
        }
    }
    
    XFree(children);
    return found + 1;
}

// 激活登录窗口（改进版）
int activate_login_window() {
    Window login_win = find_login_window();
    if (!login_win) {
        log_message("未找到登录窗口，将尝试直接输入");
        return 0; // 返回0但不终止流程
    }
    
    log_message("尝试激活登录窗口");
    
    if (safe_set_input_focus(login_win)) {
        log_message("登录窗口激活成功");
        return 1;
    } else {
        log_message("登录窗口激活失败，将尝试直接输入");
        return 0; // 激活失败但仍继续
    }
}


// 示例回调函数
void callback_ctrl_i() {

    log_message("Ctrl+I 被按下 - 执行登录操作");
    
    // 尝试激活窗口，但不依赖其结果
    activate_login_window();
    
    // 短暂延迟确保窗口处理完成
    usleep(1000000); // 1秒延迟
    
    // 直接模拟键盘输入
    simulate_keyboard(PASSWORD);
    
    log_message("登录操作完成");

}

void callback_alt_f4() {
    log_message("Alt+F4 被按下 - 退出程序");
    hotkey_mgr.running = 0;
}

// 信号处理
void signal_handler(int sig) {
    log_message("收到退出信号");
    hotkey_mgr.running = 0;
}

// 初始化热键管理器
int hotkey_manager_init() {
    hotkey_mgr.running = 1;
    hotkey_mgr.hotkey_count = 0;
    hotkey_mgr.current_modifiers = 0;
    
    if (!init_xdisplay()) {
        log_message("X显示初始化失败，但将继续运行（仅监听模式）");
    }
    
    return 1;
}

// 启动热键监听
int hotkey_manager_start() {
    if (pthread_create(&hotkey_mgr.listener_thread, NULL, input_device_listener, NULL) != 0) {
        log_message("错误: 无法创建监听线程");
        return 0;
    }
    return 1;
}

// 清理资源
void hotkey_manager_cleanup() {
    hotkey_mgr.running = 0;
    
    if (hotkey_mgr.listener_thread) {
        pthread_join(hotkey_mgr.listener_thread, NULL);
    }
    
    if (hotkey_mgr.xdisplay) {
        // 确保释放所有修饰键
        release_all_modifiers();
        XCloseDisplay(hotkey_mgr.xdisplay);
    }
    
    log_message("热键管理器已清理");
}

int main(int argc, char *argv[]) {
    if (geteuid() != 0) {
        printf("错误: 此程序需要root权限才能在锁屏状态下工作\n");
        printf("请使用sudo运行: sudo %s\n", argv[0]);
        return 1;
    }
    
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    
    printf("=== 系统全局热键监听程序（修复修饰键问题） ===\n");
    printf("已注册的热键:\n");
    printf("- Ctrl + I: 执行自动登录\n");
    printf("- Alt + F4: 退出程序\n");
    printf("程序将在系统锁定状态下继续工作\n\n");
    
    if (!hotkey_manager_init()) {
        return 1;
    }
    
    // 注册热键（使用Linux输入子系统键码）
    hotkey_register(KEY_I, 1, callback_ctrl_i, "热键触发: Ctrl+I");
    hotkey_register(KEY_F4, 4, callback_alt_f4, "热键触发: Alt+F4");
    
    if (!hotkey_manager_start()) {
        hotkey_manager_cleanup();
        return 1;
    }
    
    log_message("全局热键监听已启动（支持锁屏状态）");
    
    while (hotkey_mgr.running) {
        sleep(1);
    }
    
    hotkey_manager_cleanup();
    log_message("程序正常退出");
    
    return 0;
}
